import redis, json
from P1_python_基础.common.utils import ConfigUtils
from typing import Dict, Union
from application02.utils import LogUtil as logger


class CacheUtils:
    def __init__(self, business_type='xxx'):
        self.__source_host = ConfigUtils.get_app_config(f'redis_source.{business_type}.host')
        self.__source_port = ConfigUtils.get_app_config(f'redis_source.{business_type}.port')
        self.__source_password = ConfigUtils.get_app_config(f'redis_source.{business_type}.password')

    def __create_csc_redis_connection_pool(self):
        return redis.ConnectionPool(host=self.__source_host, port=self.__source_port, password=self.__source_password,
                                    max_connections=10) if self.__source_password else redis.ConnectionPool(
            host=self.__source_host, port=self.__source_port,
            max_connections=10)

    def del_data(self, key):
        pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=pool, decode_responses=True)
        a = None
        try:
            if len(r.keys(key)) > 0:
                a = r.delete(*r.keys(key))
        except redis.exceptions.ResponseError as e:
            logger.exception(f'换用key命令{str(e)}')
            a = r.delete(key)
        except Exception as e:
            logger.exception(str(e))
            return '删除失败'
        logger.info(f"本次删除的key:{key},删除数量{a}")
        pool.disconnect()
        return a

    def set_data(self, key, value, ttl=None):
        pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=pool, decode_responses=True)
        try:
            r.set(key, str(value), ttl)
        except Exception:
            pool.disconnect()
            return '对应Key获取到值不唯一，无法赋值内容'
        pool.disconnect()
        return

    def set_json_data(self, key, value, ttl=None):
        r = redis.Redis(connection_pool=self.__create_csc_redis_connection_pool(), decode_responses=True)
        try:
            r.set(key, json.dumps(value), ttl)
        except:
            self.__create_csc_redis_connection_pool().disconnect()
            return '对应Key获取到值不唯一，无法赋值内容'
        self.__create_csc_redis_connection_pool().disconnect()
        return

    def get_data(self, key):
        Pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=Pool, decode_responses=True)
        try:
            value = r.get(*r.keys(key))
        except:
            return
        try:
            format_data = json.loads(value)
        except:
            return value.decode()
        else:
            return format_data

    def get_other_data(self, key):
        Pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=Pool, decode_responses=True)
        value = r.get(key)
        return value

    def get_zset_value(self, key):
        Pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=Pool, decode_responses=True)
        elements = r.zrange(key, 0, -1, withscores=True)
        return elements

    def get_list_value(self, key):
        Pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=Pool, decode_responses=True)
        elements = r.lrange(key, 0, -1)
        return elements

    def set_zset_value(self, key, value):
        Pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=Pool, decode_responses=True)
        r.zadd(key, {e.decode('utf-8'): score for e, score in value})
        return

    def add_key(self, name):
        Pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=Pool, decode_responses=True)
        i = 1
        while i <= 1000:
            i += 1
            print(f'{name}-{i}')
            r.incr("my_key")
        return

    def get_redis_data(self, key: str) -> Dict[str, Union[str, list, dict]]:
        """
        获取 Redis 键值数据并结构化返回
        :param key: 要查询的键名
        :param redis_conn: Redis 连接对象
        :return: 包含数据类型和内容的字典
        """
        Pool = self.__create_csc_redis_connection_pool()
        redis_conn = redis.Redis(connection_pool=Pool, decode_responses=True)
        result = {
            "key": key,
            "type": None,
            "data": None,
            "error": None
        }

        try:
            if not redis_conn.exists(key):
                result["error"] = "Key does not exist"
                return result

            # 获取数据类型
            data_type = redis_conn.type(key).decode('utf-8')
            result["type"] = data_type

            # 根据类型获取数据
            if data_type == 'string':
                result["data"] = redis_conn.get(key)
            elif data_type == 'hash':
                result["data"] = redis_conn.hgetall(key)
            elif data_type == 'list':
                result["data"] = redis_conn.lrange(key, 0, -1)
            elif data_type == 'set':
                # 集合转为列表输出
                result["data"] = list(redis_conn.smembers(key))
            elif data_type == 'zset':
                # 有序集合带分数返回
                result["data"] = [
                    {
                        "member": member,
                        "score": score
                    }
                    for member, score in redis_conn.zrange(key, 0, -1, withscores=True)
                ]
            else:
                result["error"] = f"Unsupported data type: {data_type}"

        except redis.RedisError as e:
            result["error"] = f"Redis error: {str(e)}"
        except Exception as e:
            result["error"] = f"Unexpected error: {str(e)}"
        return result

    def scan_keys(self, key):
        cursor = 0
        matching_keys = []
        Pool = self.__create_csc_redis_connection_pool()
        r = redis.Redis(connection_pool=Pool, decode_responses=True)
        while True:
            cursor, keys = r.scan(cursor=cursor, match=key)
            matching_keys.extend(keys)
            # 如果游标返回为0，表示扫描完成
            if cursor == 0:
                break
        return [key.decode('utf-8') for key in matching_keys]


if __name__ == '__main__':
    new_cache = CacheUtils()
    get_pre = new_cache.get_redis_data(
        'GAZIMGW69P53102V:jks')

    print(get_pre)
